import sys
import os
import json
import base64
from PySide6.QtWidgets import (QApplication, QMainWindow, QPushButton, QLabel, QFileDialog,
                               QVBoxLayout, QWidget, QTableWidget, QTableWidgetItem, 
                               QHeaderView, QHBoxLayout, QFrame, QTextEdit, QLineEdit,
                               QGroupBox, QFormLayout, QMessageBox, QSplitter, QListWidget,
                               QDialog, QDialogButtonBox, QGridLayout, QProgressBar, QCheckBox,
                               QListWidgetItem)
from PySide6.QtGui import QPixmap, QImage, QFont, QColor, QIcon
from PySide6.QtCore import Qt, QDateTime, QThread, Signal, QObject, QThreadPool, QRunnable
import concurrent.futures
from functools import lru_cache

class ImageLoadTask(QRunnable):
    """图片加载任务"""
    
    def __init__(self, row, file_path, callback):
        super().__init__()
        self.row = row
        self.file_path = file_path
        self.callback = callback
        self.setAutoDelete(True)
    
    def run(self):
        try:
            # 检查文件是否存在
            if not os.path.exists(self.file_path):
                return
                
            # 使用lru_cache缓存图片加载
            image = self.load_image_cached(self.file_path)
            if not image.isNull():
                scaled_img = image.scaled(50, 50, Qt.KeepAspectRatio, Qt.SmoothTransformation)
                pixmap = QPixmap.fromImage(scaled_img)
                self.callback(self.row, pixmap)
        except Exception as e:
            print(f"图片加载失败 {self.file_path}: {e}")
    
    @lru_cache(maxsize=200)
    def load_image_cached(self, file_path):
        """带缓存的图片加载"""
        return QImage(file_path)

class ImageLoader(QObject):
    """图片加载管理器"""
    image_loaded = Signal(int, QPixmap)
    loading_progress = Signal(int, int)  # 当前进度, 总数
    loading_finished = Signal()
    
    def __init__(self):
        super().__init__()
        self.thread_pool = QThreadPool.globalInstance()
        # 根据CPU核心数设置线程数，但不要太多
        self.thread_pool.setMaxThreadCount(min(4, self.thread_pool.maxThreadCount()))
        self.pending_tasks = 0
        self.completed_tasks = 0
        self.total_tasks = 0
        
    def load_images(self, image_data, current_type):
        """异步加载图片"""
        self.pending_tasks = 0
        self.completed_tasks = 0
        self.total_tasks = len(image_data)
        
        # 分批加载，避免一次性创建太多任务
        batch_size = 10
        for i in range(0, len(image_data), batch_size):
            batch = image_data[i:i + batch_size]
            self.load_batch(batch, current_type, i)
    
    def load_batch(self, batch_data, current_type, start_index):
        """加载一批图片"""
        for offset, data in enumerate(batch_data):
            row = start_index + offset
            file_path = data[0] if current_type == "sku" else data
            
            # 创建加载任务
            task = ImageLoadTask(row, file_path, self.on_image_loaded)
            self.thread_pool.start(task)
            self.pending_tasks += 1
    
    def on_image_loaded(self, row, pixmap):
        """图片加载完成回调"""
        self.image_loaded.emit(row, pixmap)
        self.completed_tasks += 1
        self.pending_tasks -= 1
        
        # 更新进度
        self.loading_progress.emit(self.completed_tasks, self.total_tasks)
        
        # 检查是否所有任务完成
        if self.completed_tasks == self.total_tasks:
            self.loading_finished.emit()
    
    def stop(self):
        """停止加载"""
        self.thread_pool.clear()

class Base64ConversionThread(QThread):
    """Base64转换线程"""
    progress_updated = Signal(int, int)  # 当前进度, 总数
    conversion_finished = Signal(dict)   # 转换完成的数据
    
    def __init__(self, image_config, save_as_base64):
        super().__init__()
        self.image_config = image_config
        self.save_as_base64 = save_as_base64
        # 添加缓存，避免重复转换相同的图片
        self.base64_cache = {}
    
    def run(self):
        """执行base64转换"""
        try:
            converted_config = self.convert_images_to_base64(self.image_config, self.save_as_base64)
            self.conversion_finished.emit(converted_config)
        except Exception as e:
            print(f"Base64转换失败: {e}")
            # 发送空的配置，避免程序崩溃
            self.conversion_finished.emit({})
    
    def convert_images_to_base64(self, image_config, save_as_base64):
        """将图片转换为base64格式，使用缓存避免重复转换"""
        converted_config = {}
        total_images = 0
        
        # 计算总图片数量用于进度显示
        if save_as_base64:
            # 先收集所有唯一的图片路径，避免重复计数
            unique_paths = set()
            
            # 主图
            for img_path in image_config.get("main_images", []):
                if isinstance(img_path, str):  # 确保是字符串路径
                    unique_paths.add(img_path)
            
            # 详情图
            for img_path in image_config.get("detail_images", []):
                if isinstance(img_path, str):  # 确保是字符串路径
                    unique_paths.add(img_path)
            
            # SKU图
            for sku_item in image_config.get("sku_images", []):
                if isinstance(sku_item, dict) and "path" in sku_item and isinstance(sku_item["path"], str):
                    unique_paths.add(sku_item["path"])
            
            total_images = len(unique_paths)
        
        current_progress = 0
        
        # 转换主图
        if "main_images" in image_config:
            if save_as_base64:
                converted_main_images = []
                for img_path in image_config["main_images"]:
                    if isinstance(img_path, str):  # 确保是字符串路径
                        converted_main_images.append(self.convert_single_image(img_path))
                        current_progress += 1
                        self.progress_updated.emit(current_progress, total_images)
                converted_config["main_images"] = converted_main_images
            else:
                converted_config["main_images"] = image_config["main_images"]
        
        # 转换详情图（包含尺码表）
        if "detail_images" in image_config:
            if save_as_base64:
                converted_detail_images = []
                for img_path in image_config["detail_images"]:
                    if isinstance(img_path, str):  # 确保是字符串路径
                        converted_detail_images.append(self.convert_single_image(img_path))
                        current_progress += 1
                        self.progress_updated.emit(current_progress, total_images)
                converted_config["detail_images"] = converted_detail_images
            else:
                converted_config["detail_images"] = image_config["detail_images"]
        
        # 转换SKU图
        if "sku_images" in image_config:
            if save_as_base64:
                converted_sku_images = []
                for sku_item in image_config["sku_images"]:
                    if isinstance(sku_item, dict) and "path" in sku_item and isinstance(sku_item["path"], str):
                        converted_sku = {
                            "filename": os.path.basename(sku_item["path"]),
                            "data": self.image_to_base64(sku_item["path"]),
                            "price": sku_item["price"],
                            "code": sku_item["code"],
                            "is_base64": True
                        }
                        converted_sku_images.append(converted_sku)
                        current_progress += 1
                        self.progress_updated.emit(current_progress, total_images)
                converted_config["sku_images"] = converted_sku_images
            else:
                # 不转换为base64，但保持数据结构一致
                converted_sku_images = []
                for sku_item in image_config["sku_images"]:
                    if isinstance(sku_item, dict) and "path" in sku_item:
                        converted_sku = {
                            "filename": os.path.basename(sku_item["path"]),
                            "data": sku_item["path"],  # 保持原路径
                            "price": sku_item["price"],
                            "code": sku_item["code"],
                            "is_base64": False
                        }
                        converted_sku_images.append(converted_sku)
                converted_config["sku_images"] = converted_sku_images
        
        return converted_config
    
    def convert_single_image(self, img_path):
        """转换单个图片为base64格式"""
        return {
            "filename": os.path.basename(img_path),
            "data": self.image_to_base64(img_path),
            "is_base64": True
        }
    
    def image_to_base64(self, image_path):
        """将图片文件转换为base64字符串，使用缓存避免重复转换"""
        # 如果已经在缓存中，直接返回
        if image_path in self.base64_cache:
            return self.base64_cache[image_path]
            
        try:
            with open(image_path, "rb") as img_file:
                image_data = img_file.read()
                base64_data = base64.b64encode(image_data).decode('utf-8')
                # 存入缓存
                self.base64_cache[image_path] = base64_data
                return base64_data
        except Exception as e:
            print(f"转换图片失败 {image_path}: {e}")
            return ""

class ConfigTool(QMainWindow):
    def __init__(self):
        super().__init__()
        # 数据存储
        self.main_images = []    # 主图数据
        self.detail_images = []  # 详情图数据
        self.sku_data = []       # SKU图数据
        self.external_configs = []  # 存储多个外部配置 [(文件名, 配置数据), ...]
        self.current_img_type = ""
        self.size_chart_path = ""   # 尺码表图片路径
        self.image_loader = None
        self.base64_thread = None
        self.init_main_window()
        
        # 程序启动时自动扫描配置文件（不弹窗）
        self.scan_configs_on_startup()
        
    def scan_configs_on_startup(self):
        """程序启动时自动扫描configs文件夹（不弹窗）"""
        configs_dir = os.path.join(os.getcwd(), "configs")
        if os.path.exists(configs_dir):
            self.scan_configs_folder(silent=True)
        else:
            # 如果configs文件夹不存在，创建它
            try:
                os.makedirs(configs_dir, exist_ok=True)
                print(f"已创建configs文件夹: {configs_dir}")
            except Exception as e:
                print(f"创建configs文件夹失败: {e}")
    
    def scan_configs_folder(self, silent=False):
        """扫描configs文件夹中的配置文件"""
        configs_dir = os.path.join(os.getcwd(), "configs")
        if not os.path.exists(configs_dir):
            if not silent:
                QMessageBox.information(
                    self,
                    "文件夹不存在",
                    f"configs文件夹不存在：\n{configs_dir}\n已自动创建该文件夹。"
                )
            try:
                os.makedirs(configs_dir, exist_ok=True)
            except Exception as e:
                if not silent:
                    QMessageBox.warning(self, "创建失败", f"无法创建configs文件夹：\n{str(e)}")
                return
        
        # 扫描JSON文件
        json_files = []
        for file_name in os.listdir(configs_dir):
            if file_name.lower().endswith('.json'):
                json_files.append(file_name)
        
        if not json_files:
            if not silent:
                QMessageBox.information(
                    self,
                    "没有找到配置文件",
                    f"在configs文件夹中没有找到任何JSON配置文件：\n{configs_dir}"
                )
            return
        
        loaded_count = 0
        skipped_count = 0
        for file_name in json_files:
            file_path = os.path.join(configs_dir, file_name)
            try:
                with open(file_path, "r", encoding="utf-8") as f:
                    config_data = json.load(f)
                
                # 检查是否已经加载过同名文件
                existing_files = [name for name, _ in self.external_configs]
                if file_name not in existing_files:
                    self.external_configs.append((file_name, config_data))
                    # 添加到列表控件
                    item = QListWidgetItem(file_name)
                    item.setFlags(item.flags() | Qt.ItemIsUserCheckable)
                    # 修改：默认取消勾选
                    item.setCheckState(Qt.Unchecked)
                    self.config_list.addItem(item)
                    loaded_count += 1
                else:
                    skipped_count += 1
                
            except Exception as e:
                print(f"加载配置文件失败 {file_name}: {e}")
        
        # 更新状态
        checked_count = self.get_checked_config_count()
        self.external_status.setText(f"外部配置：{len(self.external_configs)}个（选中：{checked_count}个）")
        
        if loaded_count > 0 and not silent:
            # 自动选中最后一个加载的配置
            if self.config_list.count() > 0:
                self.config_list.setCurrentRow(self.config_list.count() - 1)
                self.show_selected_config(self.config_list.currentItem())
            
            # 显示扫描结果
            msg = f"扫描完成！\n\n"
            msg += f"成功加载：{loaded_count} 个配置文件\n"
            if skipped_count > 0:
                msg += f"跳过重复：{skipped_count} 个文件\n"
            msg += f"总配置数：{len(self.external_configs)} 个"
            
            QMessageBox.information(self, "扫描完成", msg)
        elif loaded_count == 0 and not silent:
            QMessageBox.information(
                self,
                "扫描完成",
                f"没有发现新的配置文件\n所有 {len(json_files)} 个文件都已经加载过了"
            )
    
    def get_checked_config_count(self):
        """获取选中的配置数量"""
        count = 0
        for i in range(self.config_list.count()):
            item = self.config_list.item(i)
            if item.checkState() == Qt.Checked:
                count += 1
        return count
    
    def get_checked_configs(self):
        """获取所有选中的配置"""
        checked_configs = []
        for i in range(self.config_list.count()):
            item = self.config_list.item(i)
            if item.checkState() == Qt.Checked:
                checked_configs.append((i, item.text()))
        return checked_configs
    
    def set_all_checked(self, checked=True):
        """设置所有项的选中状态"""
        for i in range(self.config_list.count()):
            item = self.config_list.item(i)
            item.setCheckState(Qt.Checked if checked else Qt.Unchecked)
        # 更新状态显示
        checked_count = self.get_checked_config_count()
        self.external_status.setText(f"外部配置：{len(self.external_configs)}个（选中：{checked_count}个）")
    
    def show_selected_config(self, item):
        """显示选中的外部配置详情"""
        if not item:
            return
            
        # 找到对应的配置数据
        index = self.config_list.row(item)
        if 0 <= index < len(self.external_configs):
            file_name, config_data = self.external_configs[index]
            self.external_config_text.setText(json.dumps(config_data, ensure_ascii=False, indent=4))
    
    def remove_selected_config(self):
        """移除选中的外部配置（支持多选）"""
        checked_items = self.get_checked_configs()
        if not checked_items:
            QMessageBox.warning(self, "提示", "请先选中要移除的配置文件（勾选复选框）")
            return
            
        # 确认移除
        file_names = [name for _, name in checked_items]
        file_list = "\n".join([f"• {name}" for name in file_names])
        
        reply = QMessageBox.question(
            self,
            "确认移除",
            f"确定要移除以下 {len(checked_items)} 个配置文件吗？\n\n{file_list}",
            QMessageBox.Yes | QMessageBox.No,
            QMessageBox.No
        )
        
        if reply == QMessageBox.Yes:
            # 从后往前移除，避免索引变化
            checked_items.sort(reverse=True, key=lambda x: x[0])
            
            for index, file_name in checked_items:
                # 从数据列表中移除
                del self.external_configs[index]
                # 从列表控件中移除
                self.config_list.takeItem(index)
            
            # 更新状态
            checked_count = self.get_checked_config_count()
            self.external_status.setText(f"外部配置：{len(self.external_configs)}个（选中：{checked_count}个）")
            # 清空预览
            self.external_config_text.clear()
            self.external_config_text.setPlaceholderText("请从左侧选择已加载的配置文件查看详情...")
    
    def init_main_window(self):
        """初始化主窗口（支持多外部配置）"""
        self.setWindowTitle("配置文件工具（多配置融合 + Base64支持 + 图片去重）")
        # 修改：增加窗口大小以提供更好的视觉体验
        self.setGeometry(100, 100, 1400, 1000)
        
        # 主布局
        central_widget = QWidget()
        self.setCentralWidget(central_widget)
        main_layout = QVBoxLayout(central_widget)
        
        # 1. 说明文本
        info_label = QLabel("支持加载多个外部配置文件，与图片配置融合生成完整配置（后加载的配置会覆盖先加载的同名字段）")
        info_label.setAlignment(Qt.AlignCenter)
        info_label.setStyleSheet("font-size: 14px; margin: 10px 0; padding: 8px; background-color: #e8f4fd; border-radius: 5px;")
        main_layout.addWidget(info_label)
        
        # 2. Base64配置区域
        base64_frame = QFrame()
        base64_frame.setFrameShape(QFrame.StyledPanel)
        base64_frame.setStyleSheet("margin: 5px 20px; padding: 10px; background-color: #f0f8ff; border-radius: 8px;")
        base64_layout = QHBoxLayout(base64_frame)
        
        # Base64选项
        self.base64_checkbox = QCheckBox("保存为Base64格式（自动去重）")
        self.base64_checkbox.setToolTip("将图片数据转换为Base64格式保存到配置文件中，自动去除重复图片")
        self.base64_checkbox.setStyleSheet("font-size: 14px; font-weight: bold;")
        base64_layout.addWidget(self.base64_checkbox)
        
        # Base64进度条
        base64_layout.addWidget(QLabel("转换进度:"))
        self.base64_progress = QProgressBar()
        self.base64_progress.setVisible(False)
        self.base64_progress.setMaximum(100)
        self.base64_progress.setFixedWidth(200)
        base64_layout.addWidget(self.base64_progress)
        
        base64_layout.addStretch()
        main_layout.addWidget(base64_frame)
        
        # 3. 核心功能按钮区
        core_btn_layout = QHBoxLayout()
        core_btn_layout.setSpacing(15)
        core_btn_layout.setContentsMargins(20, 0, 20, 0)
        
        # 选择图片按钮组
        select_btn_layout = QHBoxLayout()
        select_btn_layout.setSpacing(15)
        
        # 选择主图按钮
        self.main_btn = QPushButton("选择主图")
        self.main_btn.setStyleSheet("padding: 8px 16px; font-size: 14px;")
        self.main_btn.clicked.connect(lambda: self.select_images("main"))
        select_btn_layout.addWidget(self.main_btn)
        
        # 选择详情图按钮
        self.detail_btn = QPushButton("选择详情图")
        self.detail_btn.setStyleSheet("padding: 8px 16px; font-size: 14px;")
        self.detail_btn.clicked.connect(lambda: self.select_images("detail"))
        select_btn_layout.addWidget(self.detail_btn)
        
        # 添加选择尺码表按钮
        self.size_chart_btn = QPushButton("选择尺码表")
        self.size_chart_btn.setStyleSheet("padding: 8px 16px; font-size: 14px; background-color: #FF9800; color: white; border-radius: 4px;")
        self.size_chart_btn.clicked.connect(self.select_size_chart)
        select_btn_layout.addWidget(self.size_chart_btn)
        
        # 选择SKU图按钮
        self.sku_btn = QPushButton("选择SKU图")
        self.sku_btn.setStyleSheet("padding: 8px 16px; font-size: 14px;")
        self.sku_btn.clicked.connect(lambda: self.select_images("sku"))
        select_btn_layout.addWidget(self.sku_btn)
        
        # 添加低价SKU按钮
        self.low_price_sku_btn = QPushButton("添加低价SKU")
        self.low_price_sku_btn.setStyleSheet("padding: 8px 16px; font-size: 14px; background-color: #FF5722; color: white; border-radius: 4px;")
        self.low_price_sku_btn.clicked.connect(self.add_low_price_sku)
        select_btn_layout.addWidget(self.low_price_sku_btn)
        
        # 配置操作按钮组
        config_btn_layout = QHBoxLayout()
        config_btn_layout.setSpacing(15)
        
        # 加载外部配置按钮
        self.load_btn = QPushButton("加载外部配置")
        self.load_btn.setStyleSheet("padding: 8px 16px; font-size: 14px; background-color: #2196F3; color: white; border-radius: 4px;")
        self.load_btn.clicked.connect(self.load_external_configs)
        
        # 扫描配置文件按钮
        self.scan_btn = QPushButton("扫描配置文件")
        self.scan_btn.setStyleSheet("padding: 8px 16px; font-size: 14px; background-color: #9C27B0; color: white; border-radius: 4px;")
        self.scan_btn.clicked.connect(self.scan_configs_folder)
        self.scan_btn.setToolTip("扫描程序目录下configs文件夹中的JSON配置文件")
        
        # 列表操作按钮组
        list_btn_layout = QHBoxLayout()
        list_btn_layout.setSpacing(10)
        
        # 全选按钮
        self.select_all_btn = QPushButton("全选")
        self.select_all_btn.setStyleSheet("padding: 6px 12px; font-size: 12px; border-radius: 4px;")
        self.select_all_btn.clicked.connect(lambda: self.set_all_checked(True))
        
        # 全不选按钮
        self.select_none_btn = QPushButton("全不选")
        self.select_none_btn.setStyleSheet("padding: 6px 12px; font-size: 12px; border-radius: 4px;")
        self.select_none_btn.clicked.connect(lambda: self.set_all_checked(False))
        
        # 移除选中配置按钮
        self.remove_btn = QPushButton("移除选中配置")
        self.remove_btn.setStyleSheet("padding: 6px 12px; font-size: 12px; background-color: #f44336; color: white; border-radius: 4px;")
        self.remove_btn.clicked.connect(self.remove_selected_config)
        
        list_btn_layout.addWidget(self.select_all_btn)
        list_btn_layout.addWidget(self.select_none_btn)
        list_btn_layout.addWidget(self.remove_btn)
        
        # 保存融合配置按钮
        self.save_btn = QPushButton("保存融合配置")
        self.save_btn.setStyleSheet("padding: 8px 16px; font-size: 14px; background-color: #4CAF50; color: white; border-radius: 4px;")
        self.save_btn.clicked.connect(self.save_merged_config)
        
        config_btn_layout.addWidget(self.load_btn)
        config_btn_layout.addWidget(self.scan_btn)
        config_btn_layout.addLayout(list_btn_layout)
        config_btn_layout.addWidget(self.save_btn)
        
        # 加入核心按钮布局
        core_btn_layout.addLayout(select_btn_layout)
        core_btn_layout.addLayout(config_btn_layout)
        main_layout.addLayout(core_btn_layout)
        
        # 4. 配置预览区域（重新设计布局）
        preview_frame = QFrame()
        preview_frame.setFrameShape(QFrame.StyledPanel)
        preview_frame.setStyleSheet("margin: 10px 20px; padding: 10px; background-color: white; border-radius: 8px;")
        preview_layout = QVBoxLayout(preview_frame)
        
        # 预览标题
        preview_label = QLabel("配置预览：")
        preview_label.setStyleSheet("font-weight: bold; font-size: 16px; margin-bottom: 10px; color: #333;")
        preview_layout.addWidget(preview_label)
        
        # 水平分割：左侧列表，右侧预览
        h_splitter = QSplitter(Qt.Horizontal)
        h_splitter.setStyleSheet("QSplitter::handle { background-color: #ccc; }")
        
        # 左侧：已加载的外部配置列表（带复选框）
        config_list_frame = QFrame()
        config_list_frame.setStyleSheet("background-color: #f9f9f9; border-radius: 5px; padding: 5px;")
        config_list_layout = QVBoxLayout(config_list_frame)
        
        # 列表标题和操作按钮
        list_header_layout = QHBoxLayout()
        list_title = QLabel("已加载的配置：")
        list_title.setStyleSheet("font-weight: bold; margin-bottom: 5px;")
        list_header_layout.addWidget(list_title)
        list_header_layout.addStretch()
        
        # 列表操作按钮
        list_btn_layout_small = QHBoxLayout()
        self.select_all_btn_small = QPushButton("全选")
        self.select_all_btn_small.setStyleSheet("padding: 4px 8px; font-size: 11px;")
        self.select_all_btn_small.clicked.connect(lambda: self.set_all_checked(True))
        
        self.select_none_btn_small = QPushButton("全不选")
        self.select_none_btn_small.setStyleSheet("padding: 4px 8px; font-size: 11px;")
        self.select_none_btn_small.clicked.connect(lambda: self.set_all_checked(False))
        
        list_btn_layout_small.addWidget(self.select_all_btn_small)
        list_btn_layout_small.addWidget(self.select_none_btn_small)
        list_header_layout.addLayout(list_btn_layout_small)
        
        config_list_layout.addLayout(list_header_layout)
        
        # 创建带复选框的列表
        self.config_list = QListWidget()
        self.config_list.setStyleSheet("""
            QListWidget {
                background-color: white; 
                border: 1px solid #ddd; 
                border-radius: 4px;
            }
            QListWidget::item {
                padding: 5px;
                border-bottom: 1px solid #eee;
            }
            QListWidget::item:selected {
                background-color: #e3f2fd;
            }
        """)
        self.config_list.itemClicked.connect(self.show_selected_config)
        config_list_layout.addWidget(self.config_list)
        
        h_splitter.addWidget(config_list_frame)
        
        # 右侧：垂直分割两个预览框
        v_splitter = QSplitter(Qt.Vertical)
        v_splitter.setStyleSheet("QSplitter::handle { background-color: #ccc; }")
        
        # 上部分：当前图片配置
        image_config_frame = QFrame()
        image_config_layout = QVBoxLayout(image_config_frame)
        
        image_config_title = QLabel("图片配置预览：")
        image_config_title.setStyleSheet("font-weight: bold; color: #2196F3; margin-bottom: 5px;")
        image_config_layout.addWidget(image_config_title)
        
        self.image_config_text = QTextEdit()
        self.image_config_text.setReadOnly(True)
        self.image_config_text.setFont(QFont("Consolas", 10))
        self.image_config_text.setStyleSheet("""
            QTextEdit {
                background-color: #f8f9fa; 
                border: 1px solid #e0e0e0; 
                border-radius: 4px;
                padding: 5px;
            }
        """)
        self.image_config_text.setPlaceholderText("图片配置将显示在这里...")
        image_config_layout.addWidget(self.image_config_text)
        
        v_splitter.addWidget(image_config_frame)
        
        # 下部分：选中的外部配置 + 融合提示
        external_frame = QWidget()
        external_layout = QVBoxLayout(external_frame)
        
        external_config_title = QLabel("外部配置预览：")
        external_config_title.setStyleSheet("font-weight: bold; color: #9C27B0; margin-bottom: 5px;")
        external_layout.addWidget(external_config_title)
        
        self.external_config_text = QTextEdit()
        self.external_config_text.setReadOnly(True)
        self.external_config_text.setFont(QFont("Consolas", 10))
        self.external_config_text.setStyleSheet("""
            QTextEdit {
                background-color: #f3e5f5; 
                border: 1px solid #e1bee7; 
                border-radius: 4px;
                padding: 5px;
            }
        """)
        self.external_config_text.setPlaceholderText("请从左侧选择已加载的配置文件查看详情...")
        external_layout.addWidget(self.external_config_text)
        
        # 融合提示
        merge_hint = QLabel("<font color='blue'>提示：保存时将按加载顺序融合所有选中配置（后加载的覆盖先加载的同名字段）</font>")
        merge_hint.setAlignment(Qt.AlignCenter)
        merge_hint.setStyleSheet("margin-top: 5px; padding: 5px; background-color: #e8f4fd; border-radius: 4px;")
        external_layout.addWidget(merge_hint)
        
        v_splitter.addWidget(external_frame)
        
        # 修改：设置更合理的分割比例
        v_splitter.setSizes([400, 400])  # 上下两部分各占一半高度
        h_splitter.addWidget(v_splitter)
        
        # 修改：设置更合理的分割比例，左侧列表更窄
        h_splitter.setSizes([200, 1100])  # 左侧200，右侧1100
        preview_layout.addWidget(h_splitter)
        
        main_layout.addWidget(preview_frame)
        
        # 5. 状态区域
        self.status_frame = QFrame()
        self.status_frame.setFrameShape(QFrame.StyledPanel)
        self.status_frame.setStyleSheet("margin: 10px 20px; padding: 10px; background-color: #f5f5f5; border-radius: 8px;")
        status_layout = QHBoxLayout(self.status_frame)
        
        self.main_status = QLabel("主图：未选择任何文件")
        self.detail_status = QLabel("详情图：未选择任何文件")
        self.sku_status = QLabel("SKU图：未选择任何文件")
        self.external_status = QLabel("外部配置：0个（选中：0个）")  # 显示数量和选中数量
        
        self.main_status.setStyleSheet("color: gray; margin-right: 20px; padding: 4px 8px; background-color: white; border-radius: 4px;")
        self.detail_status.setStyleSheet("color: gray; margin-right: 20px; padding: 4px 8px; background-color: white; border-radius: 4px;")
        self.sku_status.setStyleSheet("color: gray; margin-right: 20px; padding: 4px 8px; background-color: white; border-radius: 4px;")
        self.external_status.setStyleSheet("color: #2196F3; padding: 4px 8px; background-color: white; border-radius: 4px;")
        
        status_layout.addWidget(self.main_status)
        status_layout.addWidget(self.detail_status)
        status_layout.addWidget(self.sku_status)
        status_layout.addWidget(self.external_status)
        status_layout.addStretch()
        
        main_layout.addWidget(self.status_frame)
        
        main_layout.addStretch()
        
        # 初始更新配置文本
        self.update_config_text()
    
    def load_external_configs(self):
        """加载多个外部配置文件"""
        file_paths, _ = QFileDialog.getOpenFileNames(
            self,
            "选择外部配置文件",
            os.getcwd(),
            "JSON文件 (*.json);;所有文件 (*.*)"
        )
        
        if not file_paths:
            return  # 用户取消选择
        
        loaded_count = 0
        for file_path in file_paths:
            try:
                with open(file_path, "r", encoding="utf-8") as f:
                    config_data = json.load(f)
                
                # 提取文件名
                file_name = os.path.basename(file_path)
                
                # 检查是否已经加载过同名文件
                existing_files = [name for name, _ in self.external_configs]
                if file_name not in existing_files:
                    # 添加到配置列表
                    self.external_configs.append((file_name, config_data))
                    # 添加到列表控件
                    item = QListWidgetItem(file_name)
                    item.setFlags(item.flags() | Qt.ItemIsUserCheckable)
                    # 修改：默认取消勾选
                    item.setCheckState(Qt.Unchecked)
                    self.config_list.addItem(item)
                    loaded_count += 1
                else:
                    QMessageBox.warning(
                        self,
                        "重复文件",
                        f"配置文件 '{file_name}' 已经加载过了，跳过重复加载"
                    )
                
            except Exception as e:
                QMessageBox.warning(
                    self,
                    "加载失败",
                    f"文件 {os.path.basename(file_path)} 加载出错：\n{str(e)}"
                )
        
        # 更新状态
        checked_count = self.get_checked_config_count()
        self.external_status.setText(f"外部配置：{len(self.external_configs)}个（选中：{checked_count}个）")
        
        if loaded_count > 0:
            QMessageBox.information(
                self,
                "加载成功",
                f"成功加载 {loaded_count} 个配置文件\n共加载 {len(self.external_configs)} 个外部配置"
            )
            # 自动选中最后一个加载的配置
            if self.config_list.count() > 0:
                self.config_list.setCurrentRow(self.config_list.count() - 1)
                self.show_selected_config(self.config_list.currentItem())

    # 其余方法保持不变...
    def select_images(self, img_type):
        """选择图片，初始化对应类型数据并更新配置"""
        type_info = {
            "main": {"title": "主图", "data": self.main_images, "status": self.main_status, 
                    "color": "green", "col_count": 3},
            "detail": {"title": "详情图", "data": self.detail_images, "status": self.detail_status, 
                      "color": "blue", "col_count": 3},
            "sku": {"title": "SKU图", "data": self.sku_data, "status": self.sku_status, 
                   "color": "purple", "col_count": 5}
        }
        
        file_types = "图片文件 (*.jpg *.jpeg *.png *.bmp *.gif);;所有文件 (*.*)"
        files, _ = QFileDialog.getOpenFileNames(self, f"选择{type_info[img_type]['title']}文件", os.getcwd(), file_types)
        
        if files:
            # 显示加载提示
            if len(files) > 20:
                QMessageBox.information(self, "加载中", f"正在加载 {len(files)} 个图片文件，请稍候...")
            
            # 初始化数据
            if img_type == "main":
                self.main_images = files
                display_data = self.main_images
            elif img_type == "detail":
                self.detail_images = files
                display_data = self.detail_images
            else:
                self.sku_data = [[path, "", ""] for path in files]
                display_data = self.sku_data
            
            # 更新状态
            type_info[img_type]["status"].setText(f"{type_info[img_type]['title']}：已选择 {len(files)} 个文件")
            type_info[img_type]["status"].setStyleSheet(f"color: {type_info[img_type]['color']}; margin-right: 20px; padding: 4px 8px; background-color: white; border-radius: 4px;")
            
            # 显示表格
            self.current_img_type = img_type
            self.show_image_table(type_info[img_type]["title"], display_data)
            
            # 更新配置文本框
            self.update_config_text()
    
    def select_size_chart(self):
        """选择尺码表图片"""
        file_types = "图片文件 (*.jpg *.jpeg *.png *.bmp *.gif);;所有文件 (*.*)"
        file_path, _ = QFileDialog.getOpenFileName(self, "选择尺码表文件", os.getcwd(), file_types)
        
        if file_path:
            self.size_chart_path = file_path
            QMessageBox.information(self, "选择成功", f"已选择尺码表文件：\n{file_path}")
            self.update_config_text()
    
    def show_image_table(self, title, display_data):
        """创建图片表格（SKU图水平布局功能区）"""
        # 新窗口
        self.result_window = QMainWindow()
        self.result_window.setWindowTitle(f"{title}列表")
        self.result_window.setGeometry(200, 200, 1200 if self.current_img_type == "sku" else 1000, 600)
        
        # 主部件与布局
        central_widget = QWidget()
        self.result_window.setCentralWidget(central_widget)
        main_layout = QVBoxLayout(central_widget)
        
        # 标题
        title_text = f"{title} - 共 {len(display_data)} 个文件"
        if self.current_img_type == "sku":
            title_text += " | 支持批量选择和批量设置"
        title_label = QLabel(title_text)
        title_label.setStyleSheet("font-size: 16px; font-weight: bold; margin: 10px 0;")
        main_layout.addWidget(title_label)
        
        # 添加进度条（仅当图片数量较多时显示）
        if len(display_data) > 10:
            self.progress_bar = QProgressBar()
            self.progress_bar.setMaximum(len(display_data))
            self.progress_bar.setValue(0)
            self.progress_bar.setVisible(True)
            main_layout.addWidget(self.progress_bar)
        else:
            self.progress_bar = None
        
        # SKU图特殊功能区（水平布局）
        if self.current_img_type == "sku":
            # 功能区容器（水平布局）
            function_frame = QFrame()
            function_frame.setFrameShape(QFrame.StyledPanel)
            function_frame.setStyleSheet("padding: 10px; margin-bottom: 10px;")
            function_layout = QHBoxLayout(function_frame)
            function_layout.setSpacing(20)
            
            # 1. 搜索过滤区（水平放置）
            search_frame = QFrame()
            search_layout = QHBoxLayout(search_frame)
            search_layout.setContentsMargins(0, 0, 0, 0)
            
            search_label = QLabel("搜索文件名：")
            self.search_input = QLineEdit()
            self.search_input.setPlaceholderText("输入关键词过滤（如：加绒）")
            self.search_input.setMinimumWidth(200)
            self.search_input.textChanged.connect(self.filter_sku_items)
            
            search_layout.addWidget(search_label)
            search_layout.addWidget(self.search_input)
            function_layout.addWidget(search_frame)
            
            # 添加分隔线
            line = QFrame()
            line.setFrameShape(QFrame.VLine)
            line.setFrameShadow(QFrame.Sunken)
            function_layout.addWidget(line)
            
            # 2. 批量设置区（水平放置）
            batch_frame = QFrame()
            batch_layout = QHBoxLayout(batch_frame)
            batch_layout.setContentsMargins(0, 0, 0, 0)
            batch_layout.setSpacing(10)
            
            # 价格设置
            price_label = QLabel("批量设置价格：")
            self.batch_price = QLineEdit()
            self.batch_price.setMaximumWidth(100)
            batch_price_btn = QPushButton("应用")
            batch_price_btn.clicked.connect(lambda: self.batch_update("price"))
            
            # 编码设置
            code_label = QLabel("批量设置编码：")
            self.batch_code = QLineEdit()
            self.batch_code.setMaximumWidth(150)
            batch_code_btn = QPushButton("应用")
            batch_code_btn.clicked.connect(lambda: self.batch_update("code"))
            
            # 添加到布局
            batch_layout.addWidget(price_label)
            batch_layout.addWidget(self.batch_price)
            batch_layout.addWidget(batch_price_btn)
            batch_layout.addSpacing(20)
            batch_layout.addWidget(code_label)
            batch_layout.addWidget(self.batch_code)
            batch_layout.addWidget(batch_code_btn)
            
            function_layout.addWidget(batch_frame)
            function_layout.addStretch()
            
            main_layout.addWidget(function_frame)
        
        # 创建表格
        self.table = QTableWidget(len(display_data), 
                                 5 if self.current_img_type == "sku" else 3)
        
        # 表格设置（SKU图支持批量选择）
        if self.current_img_type == "sku":
            self.table.setSelectionMode(QTableWidget.ExtendedSelection)
            self.table.setSelectionBehavior(QTableWidget.SelectRows)
            self.table.setDragDropMode(QTableWidget.NoDragDrop)
            self.table.itemChanged.connect(self.on_sku_item_changed)
        
        # 表头设置
        if self.current_img_type == "sku":
            self.table.setHorizontalHeaderLabels(["缩略图", "序号", "文件路径", "价格", "商家编码"])
            self.table.setColumnWidth(0, 80)
            self.table.setColumnWidth(1, 60)
            self.table.setColumnWidth(3, 100)
            self.table.setColumnWidth(4, 150)
        else:
            self.table.setHorizontalHeaderLabels(["缩略图", "序号", "文件路径"])
            self.table.setColumnWidth(0, 80)
            self.table.setColumnWidth(1, 60)
        
        # 路径列自动拉伸
        self.table.horizontalHeader().setSectionResizeMode(2, QHeaderView.Stretch)
        # 行高
        self.table.verticalHeader().setDefaultSectionSize(60)
        
        # 填充表格内容
        self.fill_table_data(display_data)
        
        main_layout.addWidget(self.table)
        
        # 关闭按钮
        close_btn = QPushButton("关闭")
        close_btn.clicked.connect(self.result_window.close)
        close_btn.setStyleSheet("padding: 8px; margin: 10px;")
        main_layout.addWidget(close_btn, alignment=Qt.AlignCenter)
        
        self.result_window.show()
    
    def fill_table_data(self, display_data, filtered_rows=None):
        """填充表格数据，支持过滤显示"""
        # 清空表格
        self.table.clearContents()
        self.table.setRowCount(len(display_data))
        
        # 记录所有行的可见状态（用于过滤）
        self.visible_rows = []
        
        for row in range(len(display_data)):
            # 如果有过滤条件且当前行不在过滤结果中，则跳过
            if filtered_rows is not None and row not in filtered_rows:
                self.table.setRowHidden(row, True)
                continue
            
            self.table.setRowHidden(row, False)
            self.visible_rows.append(row)
            
            # 1. 缩略图列 (先显示占位符)
            thumb_widget = QWidget()
            thumb_layout = QHBoxLayout(thumb_widget)
            thumb_layout.setContentsMargins(5, 5, 5, 5)
            
            # 获取图片路径
            file_path = display_data[row][0] if self.current_img_type == "sku" else display_data[row]
            
            # 显示加载中占位符
            thumb_label = QLabel("加载中...")
            thumb_label.setAlignment(Qt.AlignCenter)
            thumb_label.setProperty("row", row)  # 保存行号用于异步加载后定位
            thumb_layout.addWidget(thumb_label, alignment=Qt.AlignCenter)
            self.table.setCellWidget(row, 0, thumb_widget)
            
            # 2. 序号列
            index_item = QTableWidgetItem(str(row + 1))
            index_item.setTextAlignment(Qt.AlignCenter)
            index_item.setFlags(Qt.ItemIsEnabled)
            self.table.setItem(row, 1, index_item)
            
            # 3. 路径列
            path_item = QTableWidgetItem(file_path)
            path_item.setToolTip(file_path)
            path_item.setFlags(Qt.ItemIsEnabled)
            self.table.setItem(row, 2, path_item)
            
            # 4. SKU专属列
            if self.current_img_type == "sku":
                # 价格列
                price_item = QTableWidgetItem(display_data[row][1])
                price_item.setTextAlignment(Qt.AlignCenter)
                self.table.setItem(row, 3, price_item)
                
                # 商家编码列
                code_item = QTableWidgetItem(display_data[row][2])
                code_item.setTextAlignment(Qt.AlignCenter)
                self.table.setItem(row, 4, code_item)
        
        # 启动异步图片加载
        self.start_image_loading(display_data)
    
    def start_image_loading(self, display_data):
        """启动异步图片加载"""
        # 停止之前的加载
        if self.image_loader:
            self.image_loader.stop()
        
        # 创建新的加载器
        self.image_loader = ImageLoader()
        self.image_loader.image_loaded.connect(self.update_thumbnail)
        self.image_loader.loading_progress.connect(self.update_progress)
        self.image_loader.loading_finished.connect(self.on_loading_finished)
        
        # 开始加载
        self.image_loader.load_images(display_data, self.current_img_type)
    
    def update_thumbnail(self, row, pixmap):
        """更新缩略图"""
        # 检查行是否仍然可见
        if row < self.table.rowCount() and not self.table.isRowHidden(row):
            thumb_widget = self.table.cellWidget(row, 0)
            if thumb_widget:
                # 清除布局中的所有部件
                thumb_layout = thumb_widget.layout()
                if thumb_layout:
                    # 移除旧的标签
                    for i in reversed(range(thumb_layout.count())):
                        widget = thumb_layout.itemAt(i).widget()
                        if widget:
                            widget.setParent(None)
                    
                    # 添加新的图片标签
                    thumb_label = QLabel()
                    thumb_label.setPixmap(pixmap)
                    thumb_layout.addWidget(thumb_label, alignment=Qt.AlignCenter)
    
    def update_progress(self, current, total):
        """更新加载进度"""
        if self.progress_bar:
            self.progress_bar.setValue(current)
    
    def on_loading_finished(self):
        """图片加载完成"""
        if self.progress_bar:
            self.progress_bar.setVisible(False)
    
    def filter_sku_items(self):
        """根据搜索框内容过滤SKU项"""
        if self.current_img_type != "sku":
            return
            
        keyword = self.search_input.text().lower()
        if not keyword:
            self.fill_table_data(self.sku_data)
            return
        
        # 筛选包含关键词的行
        filtered_rows = []
        for row, sku in enumerate(self.sku_data):
            file_name = os.path.basename(sku[0]).lower()
            if keyword in file_name:
                filtered_rows.append(row)
        
        # 刷新表格
        self.fill_table_data(self.sku_data, filtered_rows)
        QMessageBox.information(self.result_window, "筛选结果", 
                              f"找到 {len(filtered_rows)} 个包含 '{keyword}' 的文件")
    
    def batch_update(self, field):
        """批量更新选中项的价格或商家编码"""
        if self.current_img_type != "sku":
            return
            
        # 获取选中的行
        selected_rows = set()
        for item in self.table.selectedItems():
            selected_rows.add(item.row())
        
        if not selected_rows:
            QMessageBox.warning(self.result_window, "提示", "请先选择要更新的项（可按住Ctrl/Shift批量选择）")
            return
        
        # 获取要更新的值
        if field == "price":
            value = self.batch_price.text()
            col = 3
            data_col = 1
        else:
            value = self.batch_code.text()
            col = 4
            data_col = 2
        
        # 更新数据
        for row in selected_rows:
            if row in self.visible_rows:
                self.sku_data[row][data_col] = value
                self.table.item(row, col).setText(value)
        
        # 更新配置文本
        self.update_config_text()
        QMessageBox.information(self.result_window, "更新成功", 
                              f"已为 {len(selected_rows)} 个选中项更新{field}")
    
    def on_sku_item_changed(self, item):
        """监听SKU表格的单元格变化"""
        if self.current_img_type == "sku" and item.column() in [3, 4]:
            row = item.row()
            col = item.column() - 2
            self.update_sku_data(row, col, item.text())
    
    def update_sku_data(self, row, col, value):
        """更新SKU图的价格或编码数据"""
        if 0 <= row < len(self.sku_data) and 1 <= col <= 2:
            self.sku_data[row][col] = value
            self.update_config_text()
        
    def update_data_after_sort(self, from_row, to_row):
        """排序后更新原始数据"""
        if self.current_img_type == "main":
            self.main_images[from_row], self.main_images[to_row] = self.main_images[to_row], self.main_images[from_row]
            self.fill_table_data(self.main_images)
        elif self.current_img_type == "detail":
            self.detail_images[from_row], self.detail_images[to_row] = self.detail_images[to_row], self.detail_images[from_row]
            self.fill_table_data(self.detail_images)
        
        self.update_config_text()
    
    def add_low_price_sku(self):
        """添加低价SKU"""
        # 检查是否已选择SKU图
        if not self.sku_data:
            QMessageBox.warning(self, "提示", "请先选择SKU图文件")
            return
        
        # 弹出输入对话框获取低价SKU信息
        dialog = QDialog(self)
        dialog.setWindowTitle("添加低价SKU")
        dialog.setModal(True)
        dialog.resize(400, 200)
        
        layout = QGridLayout(dialog)
        
        # 输入字段
        path_label = QLabel("图片路径:")
        self.low_price_path_edit = QLineEdit()
        self.low_price_path_edit.setPlaceholderText("请输入低价SKU图片路径")
        
        price_label = QLabel("价格:")
        self.low_price_edit = QLineEdit()
        self.low_price_edit.setPlaceholderText("请输入低价")
        
        code_label = QLabel("商家编码:")
        self.low_price_code_edit = QLineEdit()
        self.low_price_code_edit.setPlaceholderText("请输入商家编码")
        
        # 文件选择按钮
        browse_btn = QPushButton("浏览...")
        browse_btn.clicked.connect(self.browse_low_price_image)
        
        # 对话框按钮
        button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
        button_box.accepted.connect(dialog.accept)
        button_box.rejected.connect(dialog.reject)
        
        # 布局
        layout.addWidget(path_label, 0, 0)
        layout.addWidget(self.low_price_path_edit, 0, 1, 1, 2)
        layout.addWidget(browse_btn, 0, 3)
        layout.addWidget(price_label, 1, 0)
        layout.addWidget(self.low_price_edit, 1, 1, 1, 3)
        layout.addWidget(code_label, 2, 0)
        layout.addWidget(self.low_price_code_edit, 2, 1, 1, 3)
        layout.addWidget(button_box, 3, 0, 1, 4)
        
        if dialog.exec() == QDialog.Accepted:
            path = self.low_price_path_edit.text().strip()
            price = self.low_price_edit.text().strip()
            code = self.low_price_code_edit.text().strip()
            
            if not path or not price or not code:
                QMessageBox.warning(self, "输入错误", "请填写完整的低价SKU信息")
                return
            
            # 添加到SKU数据末尾
            self.sku_data.append([path, price, code])
            
            # 更新状态和配置文本
            self.sku_status.setText(f"SKU图：已选择 {len(self.sku_data)} 个文件")
            self.sku_status.setStyleSheet("color: purple; margin-right: 20px; padding: 4px 8px; background-color: white; border-radius: 4px;")
            self.update_config_text()
            
            QMessageBox.information(self, "添加成功", "低价SKU已添加到列表末尾")

    def browse_low_price_image(self):
        """浏览低价SKU图片"""
        file_types = "图片文件 (*.jpg *.jpeg *.png *.bmp *.gif);;所有文件 (*.*)"
        file_path, _ = QFileDialog.getOpenFileName(self, "选择低价SKU图片", os.getcwd(), file_types)
        
        if file_path:
            self.low_price_path_edit.setText(file_path)

    def save_merged_config(self):
        """保存融合后的配置（图片配置 + 选中的外部配置）"""
        # 1. 构建图片配置部分
        # 处理详情图，如果选择了尺码表，则将其放在第一位
        final_detail_images = self.detail_images.copy()
        if self.size_chart_path:
            final_detail_images.insert(0, self.size_chart_path)
        
        # 修复：使用处理后的 final_detail_images 而不是原始的 self.detail_images
        image_config = {
            "main_images": self.main_images,
            "detail_images": final_detail_images,  # 这里使用 final_detail_images
            "sku_images": [{"path": sku[0], "price": sku[1], "code": sku[2]} for sku in self.sku_data]
        }
        
        # 检查是否启用base64转换
        save_as_base64 = self.base64_checkbox.isChecked()
        
        # 2. 只融合选中的外部配置
        checked_configs = self.get_checked_configs()
        if not checked_configs:
            reply = QMessageBox.question(
                self,
                "确认保存",
                "没有选中任何外部配置，将只保存图片配置。\n确定要继续吗？",
                QMessageBox.Yes | QMessageBox.No,
                QMessageBox.No
            )
            if reply == QMessageBox.No:
                return
        
        # 计算去重后的图片数量
        if save_as_base64:
            unique_paths = set()
            # 主图
            for img_path in image_config["main_images"]:
                if isinstance(img_path, str):  # 确保是字符串
                    unique_paths.add(img_path)
            # 详情图
            for img_path in image_config["detail_images"]:
                if isinstance(img_path, str):  # 确保是字符串
                    unique_paths.add(img_path)
            # SKU图
            for sku_item in image_config["sku_images"]:
                if isinstance(sku_item, dict) and "path" in sku_item and isinstance(sku_item["path"], str):
                    unique_paths.add(sku_item["path"])
            
            total_images = len(image_config["main_images"]) + len(image_config["detail_images"]) + len(image_config["sku_images"])
            unique_count = len(unique_paths)
            
            # 显示去重信息
            if total_images > unique_count:
                QMessageBox.information(
                    self,
                    "Base64转换优化",
                    f"检测到图片路径重复，已启用自动去重优化：\n\n"
                    f"总图片引用数：{total_images} 个\n"
                    f"去重后实际图片数：{unique_count} 个\n"
                    f"节省转换：{total_images - unique_count} 次\n\n"
                    f"这将显著提高转换速度和减少文件大小！"
                )
        
        if save_as_base64:
            # 显示转换进度条
            self.base64_progress.setVisible(True)
            self.base64_progress.setValue(0)
            
            # 在单独的线程中进行base64转换
            self.base64_thread = Base64ConversionThread(image_config, save_as_base64)
            self.base64_thread.progress_updated.connect(self.on_base64_progress_updated)
            self.base64_thread.conversion_finished.connect(self.on_base64_conversion_finished)
            self.base64_thread.start()
            
            # 禁用保存按钮，防止重复点击
            self.save_btn.setEnabled(False)
            QMessageBox.information(self, "转换中", "正在将图片转换为Base64格式，请稍候...")
            return
        else:
            # 不转换为base64，直接保存
            self.finalize_save(image_config, checked_configs)
    
    def on_base64_progress_updated(self, current, total):
        """Base64转换进度更新"""
        if total > 0:
            progress_percent = int((current / total) * 100)
            self.base64_progress.setValue(progress_percent)
    
    def on_base64_conversion_finished(self, converted_config):
        """Base64转换完成"""
        # 隐藏进度条
        self.base64_progress.setVisible(False)
        # 重新启用保存按钮
        self.save_btn.setEnabled(True)
        
        # 获取选中的配置
        checked_configs = self.get_checked_configs()
        
        # 完成保存流程
        self.finalize_save(converted_config, checked_configs)
    
    def finalize_save(self, image_config, checked_configs):
        """完成保存流程"""
        # 融合选中的外部配置（按加载顺序，后加载的覆盖先加载的，最后覆盖图片配置）
        merged_config = image_config.copy()
        
        for index, file_name in checked_configs:
            config_data = self.external_configs[index][1]
            merged_config.update(config_data)  # 后加载的会覆盖之前的同名键
        
        # 添加保存时间
        merged_config["save_time"] = QDateTime.currentDateTime().toString("yyyy-MM-dd HH:mm:ss")
        # 记录融合的配置文件信息
        merged_config["merged_files"] = [name for _, name in checked_configs]
        # 记录尺码表信息
        if self.size_chart_path:
            merged_config["size_chart"] = self.size_chart_path
        # 记录是否使用base64
        merged_config["use_base64"] = self.base64_checkbox.isChecked()
        
        # 3. 弹出保存对话框
        current_date = QDateTime.currentDateTime().date().toString("yyyyMMdd")
        base64_suffix = "_base64" if self.base64_checkbox.isChecked() else ""
        default_filename = f"merged_config{base64_suffix}_{current_date}.json"
        file_path, _ = QFileDialog.getSaveFileName(
            self,
            "保存融合配置",
            os.path.join(os.getcwd(), default_filename),
            "JSON文件 (*.json);;所有文件 (*.*)"
        )
        
        if not file_path:
            return
        
        # 4. 保存融合配置
        try:
            with open(file_path, "w", encoding="utf-8") as f:
                json.dump(merged_config, f, ensure_ascii=False, indent=4)
            
            # 提示保存信息
            base64_info = "（包含Base64图片数据）" if self.base64_checkbox.isChecked() else "（使用图片路径）"
            
            # 修复：正确计算详情图数量（包含尺码表）
            detail_count = len(image_config["detail_images"])
            main_count = len(image_config["main_images"])
            sku_count = len(image_config["sku_images"])
            
            msg = f"配置已成功保存到：\n{file_path}\n\n"
            msg += f"融合内容：\n- 图片配置{base64_info}（主图{main_count}张，详情图{detail_count}张，SKU图{sku_count}张）\n"
            msg += f"- 外部配置（选中{len(checked_configs)}个文件）"
            
            # 如果包含尺码表，在消息中特别说明
            if self.size_chart_path:
                msg += f"\n\n注意：详情图中已包含尺码表图片"
            
            # 如果启用了Base64转换，显示去重信息
            if self.base64_checkbox.isChecked():
                unique_paths = set()
                # 主图
                for img_path in image_config["main_images"]:
                    if isinstance(img_path, str):  # 确保是字符串
                        unique_paths.add(img_path)
                # 详情图
                for img_path in image_config["detail_images"]:
                    if isinstance(img_path, str):  # 确保是字符串
                        unique_paths.add(img_path)
                # SKU图
                for sku_item in image_config["sku_images"]:
                    if isinstance(sku_item, dict) and "path" in sku_item and isinstance(sku_item["path"], str):
                        unique_paths.add(sku_item["path"])
                
                total_images = main_count + detail_count + sku_count
                unique_count = len(unique_paths)
                
                if total_images > unique_count:
                    msg += f"\n\nBase64优化：检测到{total_images}个图片引用，实际{unique_count}个唯一图片，节省了{total_images - unique_count}次重复转换"
            
            QMessageBox.information(self, "保存成功", msg)
            
        except Exception as e:
            QMessageBox.critical(self, "保存失败", f"配置保存出错：\n{str(e)}")
    
    def update_config_text(self):
        """更新图片配置预览文本"""
        # 处理详情图，如果选择了尺码表，则将其放在第一位
        final_detail_images = self.detail_images.copy()
        if self.size_chart_path:
            final_detail_images.insert(0, self.size_chart_path)
        
        config_dict = {
            "main_images": self.main_images,
            "detail_images": final_detail_images,
            "sku_images": [{"path": sku[0], "price": sku[1], "code": sku[2]} for sku in self.sku_data]
        }
        
        # 添加尺码表信息
        if self.size_chart_path:
            config_dict["size_chart"] = self.size_chart_path
            
        self.image_config_text.setText(json.dumps(config_dict, ensure_ascii=False, indent=4))
    
    def closeEvent(self, event):
        """窗口关闭事件，确保线程正确退出"""
        if self.image_loader:
            self.image_loader.stop()
        if self.base64_thread and self.base64_thread.isRunning():
            self.base64_thread.quit()
            self.base64_thread.wait()
        event.accept()

if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = ConfigTool()
    window.show()
    sys.exit(app.exec())